
#define COBJMACROS

#include "ai-lib.h"
#include "ai-lib-common.h"
#include "common/debug.h"

#include <stddef.h>

#define DEFINE_THIS(class,ifild,iface) (class*)((BYTE*)(iface)-offsetof(class,lp ## ifild ## Vtbl))

#define INITDONE(x)  ((IInitDone*)  &(x)->lpInitDoneVtbl) 
#define INITDONE_THIS(iface) DEFINE_THIS(SQLImpl, InitDone, iface);

#define LANGEXT(x)  ((ILanguageExtender*)  &(x)->lpLanguageExtenderVtbl)
#define LANGEXT_THIS(iface) DEFINE_THIS(SQLImpl, LanguageExtender, iface);

typedef struct {
    IInitDoneVtbl *lpInitDoneVtbl;
    ILanguageExtenderVtbl *lpLanguageExtenderVtbl;
    LONG ref;
} SQLImpl;

/////////////////////////////////////////////////////////////////////////////
// IInitDone

static HRESULT WINAPI SQL_IInitDone_QueryInterface(IInitDone *iface, REFIID riid, void **ppv)
{
       SQLImpl *This = INITDONE_THIS(iface);

    *ppv = NULL;
    if(IsEqualGUID(&IID_IUnknown, riid)) {
        SHOW("(%p)->(IID_IUnknown %p)\n", This, ppv);
        *ppv = INITDONE(This);
    }else if(IsEqualGUID(&IID_IInitDone, riid)) {
        SHOW("(%p)->(IID_IInitDone %p)\n", This, ppv);
        *ppv = INITDONE(This);
    }else if(IsEqualGUID(&IID_ILanguageExtender, riid)) {
        SHOW("(%p)->(IID_ILanguageExtender %p)\n", This, ppv);
        *ppv = LANGEXT(This);
    }

    if(*ppv) {
        IInitDone_AddRef(iface);
        return S_OK;
    }
    return E_NOINTERFACE;
};

static ULONG WINAPI SQL_IInitDone_AddRef(IInitDone *iface)
{
      SQLImpl *This = INITDONE_THIS(iface);
    LONG ref = InterlockedIncrement(&This->ref);
    SHOW("(%p) ref=%d\n", This, ref);
    return ref;
}

static ULONG WINAPI SQL_IInitDone_Release(IInitDone *iface)
{
//    _ISQLImpl *This = iface;//INITDONE_THIS(iface);
    SQLImpl *This = INITDONE_THIS(iface);
    LONG ref = InterlockedDecrement(&This->ref);

    SHOW("(%p) ref=%d\n", This, ref);

    if(!ref) {
//        if(This->file)
//            CloseHandle(This->file);
//        heap_free(This);

//        URLMON_UnlockModule();
    }

    return ref;
} 

static HRESULT WINAPI SQL_IInitDone_Init(IInitDone *iface, IDispatch *pConnection)
{
      SQLImpl *This = INITDONE_THIS(iface);
    return S_OK;
}

static HRESULT WINAPI SQL_IInitDone_Done(IInitDone *iface)
{
      SQLImpl *This = INITDONE_THIS(iface);
    return S_OK;
}

static HRESULT WINAPI SQL_IInitDone_GetInfo(IInitDone *iface, SAFEARRAY **pInfo)
{
      SQLImpl *This = INITDONE_THIS(iface);

    long lInd = 0;      
    VARIANT varVersion;
    V_VT(&varVersion) = VT_I4;
      // This component supports 2.0 version
    V_I4(&varVersion) = 2000;
    SafeArrayPutElement(*pInfo,&lInd,&varVersion);
      
    return S_OK;
}

static const struct IInitDoneVtbl SQL_IInitDoneVtbl = {
    SQL_IInitDone_QueryInterface,
    SQL_IInitDone_AddRef,
    SQL_IInitDone_Release,
    SQL_IInitDone_Init,
    SQL_IInitDone_Done,
    SQL_IInitDone_GetInfo
};

/////////////////////////////////////////////////////////////////////////////
// ILanguageExtender

static HRESULT WINAPI SQL_ILanguageExtender_QueryInterface(ILanguageExtender *iface, REFIID riid, void **ppv)
{
    SQLImpl *This = LANGEXT_THIS(iface);
    return IInitDone_QueryInterface(INITDONE(This), riid, ppv);
};

static ULONG WINAPI SQL_ILanguageExtender_AddRef(ILanguageExtender *iface)
{
    SQLImpl *This = LANGEXT_THIS(iface);
    return IInitDone_AddRef(INITDONE(This));
}

static ULONG WINAPI SQL_ILanguageExtender_Release(ILanguageExtender *iface)
{
    SQLImpl *This = LANGEXT_THIS(iface);
    return IInitDone_Release(INITDONE(This));
} 

static HRESULT WINAPI SQL_ILanguageExtender_RegisterExtensionAs(
            ILanguageExtender * iface,
            /* [out][in] */ BSTR *bstrExtensionName)
{
      SQLImpl *This = LANGEXT_THIS(iface);
    *bstrExtensionName = SysAllocString(L"AiSQL");
    return S_OK;
}

static HRESULT WINAPI SQL_ILanguageExtender_GetNProps(
            ILanguageExtender * iface,
            /* [out][in] */ long *plProps)
{
      SQLImpl *This = LANGEXT_THIS(iface);
    return S_OK;
}

static HRESULT WINAPI SQL_ILanguageExtender_FindProp(
            ILanguageExtender * iface,
            /* [in] */ BSTR bstrPropName,
            /* [out][in] */ long *plPropNum)
{
      SQLImpl *This = LANGEXT_THIS(iface);
    return S_OK;
}

static HRESULT WINAPI SQL_ILanguageExtender_GetPropName(
            ILanguageExtender * iface,
            /* [in] */ long lPropNum,
            /* [in] */ long lPropAlias,
            /* [out][in] */ BSTR *pbstrPropName)
{
      SQLImpl *This = LANGEXT_THIS(iface);
    return S_OK;
}

static HRESULT WINAPI SQL_ILanguageExtender_GetPropVal(
            ILanguageExtender * iface,
            /* [in] */ long lPropNum,
            /* [out][in] */ VARIANT *pvarPropVal)
{
      SQLImpl *This = LANGEXT_THIS(iface);
    return S_OK;
}

static HRESULT WINAPI SQL_ILanguageExtender_SetPropVal(
            ILanguageExtender * iface,
            /* [in] */ long lPropNum,
            /* [in] */ VARIANT *varPropVal)
{
      SQLImpl *This = LANGEXT_THIS(iface);
    return S_OK;
}

static HRESULT WINAPI SQL_ILanguageExtender_IsPropReadable(
            ILanguageExtender * iface,
            /* [in] */ long lPropNum,
            /* [out][in] */ BOOL *pboolPropRead)
{
      SQLImpl *This = LANGEXT_THIS(iface);
    return S_OK;
}

static HRESULT WINAPI SQL_ILanguageExtender_IsPropWritable(
            ILanguageExtender * iface,
            /* [in] */ long lPropNum,
            /* [out][in] */ BOOL *pboolPropWrite)
{
      SQLImpl *This = LANGEXT_THIS(iface);
    return S_OK;
}

static HRESULT WINAPI SQL_ILanguageExtender_GetNMethods(
            ILanguageExtender * iface,
            /* [out][in] */ long *plMethods)
{
      SQLImpl *This = LANGEXT_THIS(iface);
    return S_OK;
}

static HRESULT WINAPI SQL_ILanguageExtender_FindMethod(
            ILanguageExtender * iface,
            BSTR bstrMethodName,
            /* [out][in] */ long *plMethodNum)
{
      SQLImpl *This = LANGEXT_THIS(iface);
    return S_OK;
}

static HRESULT WINAPI SQL_ILanguageExtender_GetMethodName(
            ILanguageExtender * iface,
            /* [in] */ long lMethodNum,
            /* [in] */ long lMethodAlias,
            /* [out][in] */ BSTR *pbstrMethodName)
{
      SQLImpl *This = LANGEXT_THIS(iface);
    return S_OK;
}

static HRESULT WINAPI SQL_ILanguageExtender_GetNParams(
            ILanguageExtender * iface,
            /* [in] */ long lMethodNum,
            /* [out][in] */ long *plParams)
{
      SQLImpl *This = LANGEXT_THIS(iface);
    return S_OK;
}

static HRESULT WINAPI SQL_ILanguageExtender_GetParamDefValue(
            ILanguageExtender * iface,
            /* [in] */ long lMethodNum,
            /* [in] */ long lParamNum,
            /* [out][in] */ VARIANT *pvarParamDefValue)
{
      SQLImpl *This = LANGEXT_THIS(iface);
    return S_OK;
}

static HRESULT WINAPI SQL_ILanguageExtender_HasRetVal(
            ILanguageExtender * iface,
            /* [in] */ long lMethodNum,
            /* [out][in] */ BOOL *pboolRetValue)
{
      SQLImpl *This = LANGEXT_THIS(iface);
    return S_OK;
}

static HRESULT WINAPI SQL_ILanguageExtender_CallAsProc(
            ILanguageExtender * iface,
            /* [in] */ long lMethodNum,
            /* [in] */ SAFEARRAY **paParams)
{
      SQLImpl *This = LANGEXT_THIS(iface);
    return S_OK;
}

static HRESULT WINAPI SQL_ILanguageExtender_CallAsFunc(
            ILanguageExtender * iface,
            /* [in] */ long lMethodNum,
            /* [out][in] */ VARIANT *pvarRetValue,
            /* [in] */ SAFEARRAY **paParams)
{
      SQLImpl *This = LANGEXT_THIS(iface);
    return S_OK;
}

static const struct ILanguageExtenderVtbl SQL_ILanguageExtenderVtbl = {
    SQL_ILanguageExtender_QueryInterface,
    SQL_ILanguageExtender_AddRef,
    SQL_ILanguageExtender_Release,
    SQL_ILanguageExtender_RegisterExtensionAs,
    SQL_ILanguageExtender_GetNProps,
    SQL_ILanguageExtender_FindProp,
    SQL_ILanguageExtender_GetPropName,
    SQL_ILanguageExtender_GetPropVal,
    SQL_ILanguageExtender_SetPropVal,
    SQL_ILanguageExtender_IsPropReadable,
    SQL_ILanguageExtender_IsPropWritable,
    SQL_ILanguageExtender_GetNMethods,
    SQL_ILanguageExtender_FindMethod,
    SQL_ILanguageExtender_GetMethodName,
    SQL_ILanguageExtender_GetNParams,
    SQL_ILanguageExtender_GetParamDefValue,
    SQL_ILanguageExtender_HasRetVal,
    SQL_ILanguageExtender_CallAsProc,
    SQL_ILanguageExtender_CallAsFunc
};

/////////////////////////////////////////////////////////////////////////////
// SQL

HRESULT SQL_Create(IUnknown *pUnkOuter, LPVOID *ppObj)
{
    SQLImpl* object; 

    SHOW("(%p,%p)\n", pUnkOuter, ppObj);

    if( pUnkOuter )
        return CLASS_E_NOAGGREGATION;

    object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SQLImpl));
    if (!object)
    {
        SHOW("Out of memory\n");
        return E_OUTOFMEMORY;
    }

    object->lpInitDoneVtbl = (IInitDoneVtbl*)&SQL_IInitDoneVtbl;
    object->lpLanguageExtenderVtbl = (ILanguageExtenderVtbl*)&SQL_ILanguageExtenderVtbl;
    
    SHOW("object->lpVtbl = &InitDone_Vtbl;\n");
    
    object->ref = 1;
    *ppObj = INITDONE(object);
    //MessageBox(0,"*ppObj = object;","sql_create",MB_OK);
    return S_OK;
}
